﻿
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Runtime.CompilerServices;
    using System.Threading;
namespace WCYCReader.ImageTool
{
    [DebuggerDisplay("Image: {PixelWidth}x{PixelHeight}"), ContractVerification(false)]
    public sealed class Image : ImageBase
    {
        public const int DefaultAnimationSpeed = 300;

        public const double DefaultDensityX = 75;

        public const double DefaultDensityY = 75;

        private ImageFrameCollection _frames;

        private ImagePropertyCollection _properties;

        private Uri _uriSource;

        private OpenReadCompletedEventHandler DownloadCompletedHandler;

        private DownloadProgressChangedEventHandler DownloadProgressHandler;

        private EventHandler LoadingCompletedHandler;

        private EventHandler<UnhandledExceptionEventArgs> LoadingFailedHandler;

        public int AnimationSpeed
        {
            get;
            set;
        }

        public double DensityX
        {
            get;
            set;
        }

        public double DensityY
        {
            get;
            set;
        }

        public ImageFrameCollection Frames
        {
            get
            {
                Contract.Ensures(Contract.Result<ImageFrameCollection>() != null);
                return this._frames;
            }
        }

        public double InchHeight
        {
            get
            {
                double densityY = this.DensityY;
                if (densityY <= 0)
                {
                    densityY = 75;
                }
                return (double)base.PixelHeight / densityY;
            }
        }

        public double InchWidth
        {
            get
            {
                double densityX = this.DensityX;
                if (densityX <= 0)
                {
                    densityX = 75;
                }
                return (double)base.PixelWidth / densityX;
            }
        }

        public bool IsAnimated
        {
            get
            {
                return this._frames.Count > 0;
            }
        }

        public bool IsLoadingSynchronously
        {
            get;
            set;
        }

        public ImagePropertyCollection Properties
        {
            get
            {
                Contract.Ensures(Contract.Result<ImagePropertyCollection>() != null);
                return this._properties;
            }
        }

        public Uri UriSource
        {
            get
            {
                return this._uriSource;
            }
            set
            {
                this._uriSource = value;
                if (this._uriSource != null)
                {
                    this.LoadAsync(this._uriSource);
                }
            }
        }

        public Image()
        {
            this._frames = new ImageFrameCollection();
            this._properties = new ImagePropertyCollection();
            this.InitializeDefaults();
        }

        public Image(Image other)
            : base(other)
        {
            this._frames = new ImageFrameCollection();
            this._properties = new ImagePropertyCollection();
            Contract.Requires<ArgumentNullException>(other != null, "Other image cannot be null.");
            Contract.Requires<ArgumentException>(other.IsLoaded, "Other image has not been loaded.");
            Contract.Ensures(base.IsLoaded);
            foreach (ImageFrame frame in other.Frames)
            {
                if (frame == null)
                {
                    continue;
                }
                if (!frame.IsLoaded)
                {
                    throw new ArgumentException("The image contains a frame that has not been loaded yet.");
                }
                this.Frames.Add(new ImageFrame(frame));
            }
            this.InitializeDefaults();
        }

        public Image(int width, int height)
            : base(width, height)
        {
            this._frames = new ImageFrameCollection();
            this._properties = new ImagePropertyCollection();
            Contract.Requires<ArgumentException>(width >= 0, "Width must be greater or equals than zero.");
            Contract.Requires<ArgumentException>(height >= 0, "Height must be greater or equals than zero.");
            Contract.Ensures(base.IsLoaded);
            this.InitializeDefaults();
        }

        public static Image Apply(Image source, params IImageFilter[] filters)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            Contract.Requires<ArgumentNullException>(filters != null, "Filters cannot be null.");
            return Image.PerformAction(source, true, (ImageBase sourceImage, ImageBase targetImage) =>
            {
                IImageFilter[] imageFilterArray = filters;
                for (int i = 0; i < (int)imageFilterArray.Length; i++)
                {
                    imageFilterArray[i].Apply(targetImage);
                }
            });
        }

        public static Image Apply(Image source, Rectangle rectangle, params IImageFilter[] filters)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            Contract.Requires<ArgumentNullException>(filters != null, "Filters cannot be null.");
            return Image.PerformAction(source, true, (ImageBase sourceImage, ImageBase targetImage) =>
            {
                IImageFilter[] imageFilterArray = filters;
                for (int i = 0; i < (int)imageFilterArray.Length; i++)
                {
                    imageFilterArray[i].Apply(targetImage, rectangle);
                }
            });
        }

        public Image Clone()
        {
            Contract.Requires(base.IsLoaded);
            Contract.Ensures(Contract.Result<Image>() != null);
            return new Image(this);
        }

        public static Image Crop(Image source, Rectangle bounds)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            return Image.PerformAction(source, false, (ImageBase sourceImage, ImageBase targetImage) => ImageBase.Crop(sourceImage, targetImage, bounds));
        }

        private void InitializeDefaults()
        {
            this.AnimationSpeed = 300;
            this.DensityX = 75;
            this.DensityY = 75;
        }

        private void Load(Stream stream)
        {
            Contract.Requires(stream != null);
            IEnumerable<IImageDecoder> availableDecoders = Decoders.GetAvailableDecoders();
            int num = 0;
            foreach (IImageDecoder availableDecoder in availableDecoders)
            {
                if (availableDecoder == null)
                {
                    continue;
                }
                num = Math.Max(num, availableDecoder.HeaderSize);
            }
            bool flag = false;
            Contract.Assume(num > 0);
            using (BufferedStream bufferedStream = new BufferedStream(stream, num))
            {
                byte[] numArray = new byte[num];
                bufferedStream.Read(numArray, 0, num);
                bufferedStream.Reset();
                foreach (IImageDecoder imageDecoder in availableDecoders)
                {
                    if (imageDecoder == null || !imageDecoder.IsSupportedFileFormat(numArray))
                    {
                        continue;
                    }
                    imageDecoder.Decode(this, bufferedStream);
                    flag = true;
                    if (!flag)
                    {
                        throw new UnsupportedImageFormatException();
                    }
                    return;
                }
            }
            if (!flag)
            {
                throw new UnsupportedImageFormatException();
            }
        }

        private void LoadAsync(Stream stream)
        {
            WaitCallback waitCallback = null;
            Contract.Requires(stream != null);
            if (!this.IsLoadingSynchronously)
            {
                if (waitCallback == null)
                {
                    waitCallback = (object x) =>
                    {
                        try
                        {
                            this.Load(x as Stream);
                            this.OnLoadingCompleted(EventArgs.Empty);
                        }
                        catch (Exception exception)
                        {
                            this.OnLoadingFailed(new UnhandledExceptionEventArgs(exception, false));
                        }
                    };
                }
                ThreadPool.QueueUserWorkItem(waitCallback, stream);
            }
            else
            {
                try
                {
                    this.Load(stream);
                    this.OnLoadingCompleted(EventArgs.Empty);
                }
                catch (Exception exception2)
                {
                    Exception exception1 = exception2;
                    this.OnLoadingFailed(new UnhandledExceptionEventArgs(exception1, false));
                    throw exception1;
                }
            }
        }

        private void LoadAsync(Uri uri)
        {
            Contract.Requires(uri != null);
            try
            {
                bool flag = false;
                if (!uri.IsAbsoluteUri)
                {
                    Stream localResourceStream = Extensions.GetLocalResourceStream(uri);
                    if (localResourceStream != null)
                    {
                        this.LoadAsync(localResourceStream);
                        flag = true;
                    }
                }
                if (!flag)
                {
                    WebClient webClient = new WebClient();
                    webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(this.webClient_DownloadProgressChanged);
                    webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(this.webClient_OpenReadCompleted);
                    webClient.OpenReadAsync(uri);
                }
            }
            catch (Exception exception)
            {
                this.OnLoadingFailed(new UnhandledExceptionEventArgs(exception, false));
            }
        }

        private void OnDownloadCompleted(OpenReadCompletedEventArgs e)
        {
            OpenReadCompletedEventHandler downloadCompletedHandler = this.DownloadCompletedHandler;
            if (downloadCompletedHandler != null)
            {
                downloadCompletedHandler(this, e);
            }
        }

        private void OnDownloadProgress(DownloadProgressChangedEventArgs e)
        {
            DownloadProgressChangedEventHandler downloadProgressHandler = this.DownloadProgressHandler;
            if (downloadProgressHandler != null)
            {
                downloadProgressHandler(this, e);
            }
        }

        private void OnLoadingCompleted(EventArgs e)
        {
            EventHandler loadingCompletedHandler = this.LoadingCompletedHandler;
            if (loadingCompletedHandler != null)
            {
                loadingCompletedHandler(this, e);
            }
        }

        private void OnLoadingFailed(UnhandledExceptionEventArgs e)
        {
            EventHandler<UnhandledExceptionEventArgs> loadingFailedHandler = this.LoadingFailedHandler;
            if (loadingFailedHandler != null)
            {
                loadingFailedHandler(this, e);
            }
        }

        [ContractVerification(false)]
        private static Image PerformAction(Image source, bool clone, Action<ImageBase, ImageBase> action)
        {
            Image.VerifyHasLoaded(source);
            Image image = (clone ? new Image(source) : new Image());
            action(source, image);
            foreach (ImageFrame frame in source.Frames)
            {
                ImageFrame imageFrame = new ImageFrame();
                action(frame, imageFrame);
                if (clone)
                {
                    continue;
                }
                image.Frames.Add(imageFrame);
            }
            return image;
        }

        public static Image Resize(Image source, int size, IImageResizer resizer)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            Contract.Requires<ArgumentNullException>(resizer != null, "Image Resizer cannot be null.");
            int num = 0;
            int num1 = 0;
            float pixelWidth = (float)source.PixelWidth / (float)source.PixelHeight;
            if (source.PixelWidth <= source.PixelHeight || pixelWidth <= 0f)
            {
                num1 = size;
                num = (int)((float)num1 * pixelWidth);
            }
            else
            {
                num = size;
                num1 = (int)((float)num / pixelWidth);
            }
            return Image.PerformAction(source, false, (ImageBase sourceImage, ImageBase targetImage) => resizer.Resize(sourceImage, targetImage, num, num1));
        }

        public static Image Resize(Image source, int width, int height, IImageResizer resizer)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            Contract.Requires<ArgumentNullException>(resizer != null, "Image Resizer cannot be null.");
            return Image.PerformAction(source, false, (ImageBase sourceImage, ImageBase targetImage) => resizer.Resize(sourceImage, targetImage, width, height));
        }

        public void SetSource(Stream stream)
        {
            Contract.Requires<ArgumentNullException>(stream != null, "Stream cannot be null.");
            if (this._uriSource == null)
            {
                this.LoadAsync(stream);
            }
        }

        public static Image Transform(Image source, RotationType rotationType, FlippingType flippingType)
        {
            Contract.Requires<ArgumentNullException>(source != null, "Source image cannot be null.");
            Contract.Requires<ArgumentException>(source.IsLoaded, "Source image has not been loaded.");
            return Image.PerformAction(source, false, (ImageBase sourceImage, ImageBase targetImage) => ImageBase.Transform(sourceImage, targetImage, rotationType, flippingType));
        }

        private static void VerifyHasLoaded(Image image)
        {
            Contract.Requires(image != null);
            if (!image.IsLoaded)
            {
                throw new InvalidOperationException("Image has not been loaded");
            }
            foreach (ImageFrame frame in image.Frames)
            {
                if (frame == null || !frame.IsLoaded)
                {
                    continue;
                }
                throw new InvalidOperationException("Not all frames has been loaded yet.");
            }
        }

        private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            this.OnDownloadProgress(e);
        }

        private void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                this.OnLoadingFailed(new UnhandledExceptionEventArgs(e.Error, false));
            }
            else
            {
                Contract.Assume(e.Result != null);
                this.LoadAsync(e.Result);
            }
            this.OnDownloadCompleted(e);
        }

        public event OpenReadCompletedEventHandler DownloadCompleted
        {
            add
            {
                OpenReadCompletedEventHandler openReadCompletedEventHandler;
                OpenReadCompletedEventHandler downloadCompletedHandler = this.DownloadCompletedHandler;
                do
                {
                    openReadCompletedEventHandler = downloadCompletedHandler;
                    OpenReadCompletedEventHandler openReadCompletedEventHandler1 = (OpenReadCompletedEventHandler)Delegate.Combine(openReadCompletedEventHandler, value);
                    downloadCompletedHandler = Interlocked.CompareExchange<OpenReadCompletedEventHandler>(ref this.DownloadCompletedHandler, openReadCompletedEventHandler1, openReadCompletedEventHandler);
                }
                while (downloadCompletedHandler != openReadCompletedEventHandler);
            }
            remove
            {
                OpenReadCompletedEventHandler openReadCompletedEventHandler;
                OpenReadCompletedEventHandler downloadCompletedHandler = this.DownloadCompletedHandler;
                do
                {
                    openReadCompletedEventHandler = downloadCompletedHandler;
                    OpenReadCompletedEventHandler openReadCompletedEventHandler1 = (OpenReadCompletedEventHandler)Delegate.Remove(openReadCompletedEventHandler, value);
                    downloadCompletedHandler = Interlocked.CompareExchange<OpenReadCompletedEventHandler>(ref this.DownloadCompletedHandler, openReadCompletedEventHandler1, openReadCompletedEventHandler);
                }
                while (downloadCompletedHandler != openReadCompletedEventHandler);
            }
        }

        public event DownloadProgressChangedEventHandler DownloadProgress
        {
            add
            {
                DownloadProgressChangedEventHandler downloadProgressChangedEventHandler;
                DownloadProgressChangedEventHandler downloadProgressHandler = this.DownloadProgressHandler;
                do
                {
                    downloadProgressChangedEventHandler = downloadProgressHandler;
                    DownloadProgressChangedEventHandler downloadProgressChangedEventHandler1 = (DownloadProgressChangedEventHandler)Delegate.Combine(downloadProgressChangedEventHandler, value);
                    downloadProgressHandler = Interlocked.CompareExchange<DownloadProgressChangedEventHandler>(ref this.DownloadProgressHandler, downloadProgressChangedEventHandler1, downloadProgressChangedEventHandler);
                }
                while (downloadProgressHandler != downloadProgressChangedEventHandler);
            }
            remove
            {
                DownloadProgressChangedEventHandler downloadProgressChangedEventHandler;
                DownloadProgressChangedEventHandler downloadProgressHandler = this.DownloadProgressHandler;
                do
                {
                    downloadProgressChangedEventHandler = downloadProgressHandler;
                    DownloadProgressChangedEventHandler downloadProgressChangedEventHandler1 = (DownloadProgressChangedEventHandler)Delegate.Remove(downloadProgressChangedEventHandler, value);
                    downloadProgressHandler = Interlocked.CompareExchange<DownloadProgressChangedEventHandler>(ref this.DownloadProgressHandler, downloadProgressChangedEventHandler1, downloadProgressChangedEventHandler);
                }
                while (downloadProgressHandler != downloadProgressChangedEventHandler);
            }
        }

        public event EventHandler LoadingCompleted
        {
            add
            {
                EventHandler eventHandler;
                EventHandler loadingCompletedHandler = this.LoadingCompletedHandler;
                do
                {
                    eventHandler = loadingCompletedHandler;
                    EventHandler eventHandler1 = (EventHandler)Delegate.Combine(eventHandler, value);
                    loadingCompletedHandler = Interlocked.CompareExchange<EventHandler>(ref this.LoadingCompletedHandler, eventHandler1, eventHandler);
                }
                while (loadingCompletedHandler != eventHandler);
            }
            remove
            {
                EventHandler eventHandler;
                EventHandler loadingCompletedHandler = this.LoadingCompletedHandler;
                do
                {
                    eventHandler = loadingCompletedHandler;
                    EventHandler eventHandler1 = (EventHandler)Delegate.Remove(eventHandler, value);
                    loadingCompletedHandler = Interlocked.CompareExchange<EventHandler>(ref this.LoadingCompletedHandler, eventHandler1, eventHandler);
                }
                while (loadingCompletedHandler != eventHandler);
            }
        }

        public event EventHandler<UnhandledExceptionEventArgs> LoadingFailed
        {
            add
            {
                EventHandler<UnhandledExceptionEventArgs> eventHandler;
                EventHandler<UnhandledExceptionEventArgs> loadingFailedHandler = this.LoadingFailedHandler;
                do
                {
                    eventHandler = loadingFailedHandler;
                    EventHandler<UnhandledExceptionEventArgs> eventHandler1 = (EventHandler<UnhandledExceptionEventArgs>)Delegate.Combine(eventHandler, value);
                    loadingFailedHandler = Interlocked.CompareExchange<EventHandler<UnhandledExceptionEventArgs>>(ref this.LoadingFailedHandler, eventHandler1, eventHandler);
                }
                while (loadingFailedHandler != eventHandler);
            }
            remove
            {
                EventHandler<UnhandledExceptionEventArgs> eventHandler;
                EventHandler<UnhandledExceptionEventArgs> loadingFailedHandler = this.LoadingFailedHandler;
                do
                {
                    eventHandler = loadingFailedHandler;
                    EventHandler<UnhandledExceptionEventArgs> eventHandler1 = (EventHandler<UnhandledExceptionEventArgs>)Delegate.Remove(eventHandler, value);
                    loadingFailedHandler = Interlocked.CompareExchange<EventHandler<UnhandledExceptionEventArgs>>(ref this.LoadingFailedHandler, eventHandler1, eventHandler);
                }
                while (loadingFailedHandler != eventHandler);
            }
        }
    }
}

